//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "UI/Widgets/Widget.h"
#include "UI/Systems/UserInterface.h"

namespace Engine
{
namespace UI
{

	class TextBox;
	SHARED_POINTER( TextBox );



	//
	// Label
	//

	class TextBox : public Widget
	{
		friend struct ::MetaData::TextBoxCfg;

	// variables
	protected:
		UIImage				_image;
		UIFont				_font;
		ext_string			_text;
		ext_string			_formatedText;
		vec2				_minMaxTextSize;
		rect				_textRegion;
		rect				_textMargin;
		float				_textSize;
		ColorStyle::EType	_state;


	// methods
	public:
		TextBox (EWidget::type wgtType, const EngineSubSystemsRef ess);
		~TextBox ();
		
		void SetText (const ext_string &text);

		virtual bool ProcessMessage (const WidgetMsg &msg) override;

		static TextBoxPtr	New (const EngineSubSystemsRef ess);


	protected:
		bool _Arrange (const WidgetMsg &msg);
		
		bool _Update (const WidgetMsg &msg);
		bool _Draw (const WidgetMsg &msg);
		
		bool _SetColorStyle (const WidgetMsg &msg);
	};

	

/*
=================================================
	constructor
=================================================
*/
	inline TextBox::TextBox (EWidget::type wgtType, const EngineSubSystemsRef ess) :
		Widget(wgtType, ess), _textSize(0.0f), _state(ColorStyle::IDLE)
	{
	}

/*
=================================================
	destructor
=================================================
*/
	inline TextBox::~TextBox ()
	{
	}
		
/*
=================================================
	ProcessMessage
=================================================
*/
	inline bool TextBox::ProcessMessage (const WidgetMsg &msg)
	{
		typedef WidgetMsg	WM;

		switch ( msg.GetType() )
		{
			case WM::UPDATE	 :			return _Update( msg );
			case WM::DRAW :				return _Draw( msg );
			case WM::ARRANGE :			return _Arrange( msg );
			case WM::SET_COLOR_STYLE :	return _SetColorStyle( msg );
		}

		return Widget::ProcessMessage( msg );
	}
	
/*
=================================================
	New
=================================================
*/
	inline TextBoxPtr  TextBox::New (const EngineSubSystemsRef ess)
	{
		return BaseObject::_New( new TextBox( EWidget::TEXTBOX, ess ) );
	}
	
/*
=================================================
	_Arrange
=================================================
*/
	inline bool TextBox::_Arrange (const WidgetMsg &msg)
	{
		typedef WidgetMsg		WM;

		ArrangeHelper const &	helper		= *msg.To< WM::Arrange >().helper;
		WidgetLayout			layout		= helper.GetLayout( _layouts );
		float					font_scale	= 0.0f;
		bool					auto_size	= helper.IsAutoSize( layout );

		LocaleCharacters const &	lu	= ESS()->GetUserInterface()->GetLocaleManager()->GetLocaleUtils();
		
		_visibleForLayout = helper.IsVisibleForLayout( _layoutMask );

		if ( not _visibleForLayout )
			return true;

		_image.OnLoad();

		if ( IsZero( _textSize ) )
		{
			if ( IsZero( _minMaxTextSize[1] ) )
			{
				WARNING( "can't calculate size of widget" );
				return false;
			}
			_textSize = _minMaxTextSize[1];
		}

		CHECK_ERR( _font.GetFont().IsNotNull() );

		helper.CalcFontHeight( font_scale, layout.measure, _textSize );
		_font.SetScale( font_scale );

		rect	text_margin;
		helper.TransformSize( text_margin.LeftBottom(), layout.measure, _textMargin.LeftBottom() );
		helper.TransformSize( text_margin.RightTop(),   layout.measure, _textMargin.RightTop()   );

		vec2 const	margin_size = vec2( text_margin.left + text_margin.right, text_margin.bottom + text_margin.top );

		if ( auto_size )
		{
			vec2		dim;
			float const	width = GetParent()->GetRegion().Width();

			_font.GetFormattedText( _text, width, lu, dim, _formatedText );
			helper.UnTransformSize( layout.size, layout.measure, dim + margin_size );

			auto_size = false;
		}
		
		helper.Arrange( _region, layout, _parent->GetRegion(), _parent->GetDockRegion() );

		_textRegion.LeftBottom() = _region.LeftBottom() + text_margin.LeftBottom();
		_textRegion.RightTop()   = _region.RightTop()   - text_margin.RightTop();

		vec2	dim;
		_font.GetFormattedText( _text, _textRegion.GetSize().x, lu, dim, _formatedText );


		// can change text size
		if ( IsNotZero( _minMaxTextSize.x ) and _textRegion.Height() < dim.y )
		{
			vec2	min_dim;
			float	min_scale = 0.0f;

			helper.CalcFontHeight( min_scale, layout.measure, _minMaxTextSize.x );

			_font.SetScale( min_scale );
			_font.GetFormattedText( _text, _textRegion.GetSize().x, lu, min_dim, _formatedText );

			line2d	line( vec2( min_scale, min_dim.y ), vec2( font_scale, dim.y ) );

			float	new_size = Max( line.GetXfromY( _textRegion.Height() ), min_scale );
			
			_font.SetScale( new_size );
			_font.GetFormattedText( _text, _textRegion.GetSize().x, lu, dim, _formatedText );
		}
		else
		if ( IsNotZero( _minMaxTextSize.y ) and _textRegion.Height() > dim.y )
		{
			vec2	max_dim;
			float	max_scale = 0.0f;
			
			helper.CalcFontHeight( max_scale, layout.measure, _minMaxTextSize.y );

			_font.SetScale( max_scale );
			_font.GetFormattedText( _text, _textRegion.GetSize().x, lu, max_dim, _formatedText );
			
			line2d	line( vec2( max_scale, max_dim.y ), vec2( font_scale, dim.y ) );

			float	new_size = Min( line.GetXfromY( _textRegion.Height() ), max_scale );
			
			if ( IsNotZero( new_size ) )
			{
				_font.SetScale( new_size );
				_font.GetFormattedText( _text, _textRegion.GetSize().x, lu, dim, _formatedText );
			}
		}
		
		_dockRegion = _region;

		_stateChanged = true;

		_SendToAllAttached( msg );
		return true;
	}
	
/*
=================================================
	_Update
=================================================
*/
	inline bool TextBox::_Update (const WidgetMsg &msg)
	{
		if ( not IsVisible() )
			return true;

		const Graphics::BatchRenderPtr &	br = ESS()->GetGraphicsEngine()->GetBatchRender().ptr();
		
		_state = _enabled ? ColorStyle::IDLE : ColorStyle::DISABLED;

		_CheckChangedOnUpdate( msg );

		_SendToAllAttached( msg );
		return true;
	}
	
/*
=================================================
	_Draw
=================================================
*/
	inline bool TextBox::_Draw (const WidgetMsg &msg)
	{
		if ( not IsVisible() )
			return true;

		const Graphics::BatchRenderPtr &	br = ESS()->GetGraphicsEngine()->GetBatchRender().ptr();
		
		if ( _image.IsValid() )
			_image.Draw( br, _region, _state );

		if ( not _formatedText.Empty() )
		{
			_font.SetStyle( _state );
			_font.Draw( _textRegion, _formatedText );
		}

		_SendToAllAttached( msg );
		return true;
	}

/*
=================================================
	_SetColorStyle
=================================================
*/
	inline bool TextBox::_SetColorStyle (const WidgetMsg &msg)
	{
		typedef WidgetMsg	WM;

		WM::SetColorStyle const &	scs = msg.To< WM::SetColorStyle >();

		switch ( scs.target )
		{
			case WM::SetColorStyle::FONT_CS :
				_font.SetColorStyle( scs.cs );
				return true;

			case WM::SetColorStyle::IMAGE_CS :
				_image.SetColorStyle( scs.cs );
				return true;
		}
		return false;
	}

/*
=================================================
	SetText
=================================================
*/
	inline void TextBox::SetText (const ext_string &text)
	{
		_text = text;
		_stateChanged = true;
	}


}	// UI
}	// Engine